import { useCallback, useEffect, useReducer, useRef, useMemo } from 'react';
import { LooseAny } from '@material/typeing';

export enum RequestStatus {
    IDLE = 'idle',
    LOADING = 'loading',
    SUCCESS = 'success',
    ERROR = 'error'
}

export type ApiResponse<D = LooseAny> = [0, D] | [1, LooseAny];

export type RequestState<D> = {
    status: RequestStatus;
    data?: D;
    error?: string;
};

type RequestAction<T> =
    | { type: RequestStatus.LOADING }
    | { type: RequestStatus.SUCCESS; payload: T }
    | { type: RequestStatus.ERROR; error: string };

export interface UseRequestOptions<D, P extends any[] = any[]> {
    manual?: boolean;
    formatResult?: (data: LooseAny) => D;
    onSuccess?: (data: D) => void;
    onError?: (error: string) => void;
    trackLoading?: boolean;
    initialArgs?: P; // 添加 initialArgs 选项
}

const requestReducer = <D>(state: RequestState<D>, action: RequestAction<D>): RequestState<D> => {
    if (action.type === RequestStatus.LOADING && state.status === RequestStatus.LOADING)
        return state;
    if (action.type === RequestStatus.SUCCESS && state.status === RequestStatus.SUCCESS) {
        return state.data === (action as { payload: D }).payload
            ? state
            : { ...state, status: action.type, data: (action as { payload: D }).payload };
    }
    if (
        action.type === RequestStatus.ERROR &&
        state.status === RequestStatus.ERROR &&
        state.error === (action as { error: string }).error
    )
        return state;

    switch (action.type) {
        case RequestStatus.LOADING:
            return { ...state, status: RequestStatus.LOADING, error: undefined };
        case RequestStatus.SUCCESS:
            return {
                ...state,
                status: RequestStatus.SUCCESS,
                data: (action as { payload: D }).payload,
                error: undefined
            };
        case RequestStatus.ERROR:
            return {
                ...state,
                status: RequestStatus.ERROR,
                error: (action as { error: string }).error
            };
        default:
            return state;
    }
};

// 基础请求处理（所有错误内部消化）
const baseRequest = async <D>(requestFn: () => Promise<ApiResponse>): Promise<ApiResponse<D>> => {
    try {
        return await requestFn();
    } catch (error) {
        // 网络错误等异常转为错误信息（不抛异常）
        return [1, error];
    }
};

export function useRequest<D, P extends any[] = []>(
    requestFn: (...args: P) => Promise<LooseAny>,
    options?: UseRequestOptions<D, P> // 改为可选参数
) {
    // 解构选项参数，提供默认值
    const {
        manual = false,
        formatResult,
        onSuccess,
        onError,
        trackLoading = false,
        initialArgs = [] as unknown as P // 默认值处理
    } = options || {};

    // 存储初始参数（解决引用变化问题）
    const initialArgsRef = useRef<P>(initialArgs);
    // 跟踪是否已执行过自动请求（核心：防止重复执行）
    const hasAutoExecutedRef = useRef(false);
    // 用ref存储可能变化的回调（避免executeRequest依赖变化）
    const callbacksRef = useRef({ formatResult, onSuccess, onError });

    // 实时更新回调ref（不影响executeRequest引用）
    useEffect(() => {
        callbacksRef.current = { formatResult, onSuccess, onError };
    }, [formatResult, onSuccess, onError]);

    const initialState: RequestState<D> = useMemo(
        () => ({
            status: RequestStatus.IDLE,
            data: undefined,
            error: undefined
        }),
        []
    );

    const [state, dispatch] = useReducer(requestReducer<D>, initialState);
    const requestRef = useRef(requestFn);
    const argsRef = useRef<P>(initialArgsRef.current);
    const isMountedRef = useRef(true);
    const isLoadingRef = useRef(false);

    // 核心优化：完全稳定的executeRequest（无外部依赖变化）
    const executeRequest = useCallback(
        async (...args: P) => {
            if (!isMountedRef.current) return;
            if (isLoadingRef.current) return;

            const currentArgs = args.length > 0 ? args : argsRef.current;
            argsRef.current = currentArgs;
            if (trackLoading) {
                dispatch({ type: RequestStatus.LOADING });
            }
            isLoadingRef.current = true;

            try {
                const [err, data] = await baseRequest<D>(() => requestRef.current(...currentArgs));

                const { formatResult, onSuccess, onError } = callbacksRef.current;

                if (err === 0) {
                    const formattedData = formatResult ? formatResult(data) : (data as D);
                    dispatch({ type: RequestStatus.SUCCESS, payload: formattedData });
                    onSuccess?.(formattedData);
                    return formattedData;
                }
                const errorMsg = data as string;
                dispatch({ type: RequestStatus.ERROR, error: errorMsg });
                onError?.(errorMsg);
                return undefined;
            } finally {
                isLoadingRef.current = false;
            }
        },
        [trackLoading]
    ); // 仅依赖trackLoading（基本不变）

    // 手动触发请求
    const run = useCallback(
        (...args: P): Promise<D | undefined> => {
            if (isLoadingRef.current) return Promise.resolve(undefined);
            return executeRequest(...args);
        },
        [executeRequest]
    );

    // 刷新请求
    const refresh = useCallback(() => {
        if (!isLoadingRef.current) {
            return executeRequest(...argsRef.current);
        }
    }, [executeRequest]);

    // 手动修改数据
    const mutate = useCallback(
        (data: D | ((prev?: D) => D | undefined)) => {
            const newData =
                typeof data === 'function'
                    ? (data as (prev?: D) => D | undefined)(state.data)
                    : data;
            dispatch({ type: RequestStatus.SUCCESS, payload: newData as D });
        },
        [state.data]
    );

    // 修复自动执行死循环：仅在首次满足条件时执行一次
    useEffect(() => {
        // 条件：非手动模式 + 未执行过 + 不在加载中
        if (!manual && !hasAutoExecutedRef.current && !isLoadingRef.current) {
            hasAutoExecutedRef.current = true; // 标记为已执行
            executeRequest(...initialArgsRef.current);
        }
        // 当manual从true变为false时，允许重新执行
        if (manual) {
            hasAutoExecutedRef.current = false; // 重置执行状态
        }
    }, [manual, executeRequest]);

    // 组件卸载处理
    useEffect(() => {
        isMountedRef.current = true;
        return () => {
            isMountedRef.current = false;
            isLoadingRef.current = false;
        };
    }, []);

    return useMemo(
        () => ({
            ...state,
            run,
            refresh,
            mutate,
            isLoading: isLoadingRef.current
        }),
        [state, run, refresh, mutate]
    );
}
